package domain;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.hibernate.FetchMode;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.Restrictions;

import util.HibernateUtil;

public class DAOContact implements IDAOContact{
	
	@Override
	public boolean addContact(String firstname, String lastname, String email,
			String street, String city, String zip, String country,Set<PhoneNumber> phones,Set<ContactGroup>books) {

		Contact contact = new Contact();
		contact.setEmail(email);
		contact.setFirstName(firstname);
		contact.setLastName(lastname);	
		
		Address address = new Address();
		
		address.setCity(city);
		address.setCountry(country);
		address.setStreet(street);
		address.setZip(zip);
		
		contact.setAddress(address);	
		
		if ( contact.getPhones() == null ){
			Set<PhoneNumber>tmp = new HashSet<PhoneNumber>();
			contact.setPhones(tmp);
		}
		
		Iterator<PhoneNumber> it = phones.iterator();
		while (it.hasNext()){
			PhoneNumber x = it.next();
			x.setContact(contact);
			contact.getPhones().add(x);
		}
		
		Iterator<ContactGroup> it2 = books.iterator();
		while (it2.hasNext()){
			ContactGroup g = it2.next();
			if (g.getContacts() == null)
				g.setContacts(new HashSet<Contact>());
			g.getContacts().add(contact);
			if (contact.getBooks() == null)
				contact.setBooks(new HashSet<ContactGroup>());
			contact.getBooks().add(g);
			
		}
			
		try{
			
			SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
			Session session = sessionFactory.openSession();
			
			//Ouverture de la transaction
			org.hibernate.Transaction tx = session.beginTransaction();			

			session.save(contact);
			
			tx.commit();
		
			session.close();
			
		} catch ( Exception e ){
			System.out.println("Erreur : "+e.getMessage());
			return false;
		}
		
		return true;
		
	}

	
	@Override
	public boolean deleteContact(Contact contact) {
		
		try{
			
			SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
			Session session = sessionFactory.openSession();
			
			//Ouverture de la transaction
			org.hibernate.Transaction tx = session.beginTransaction();
						
			session.delete(contact);
			
			tx.commit();
		
			session.close();
			
		} catch ( Exception e ){
			System.out.println("Erreur : "+e.getMessage());
			return false;
		}
		
		return true;
	}
	
	@Override
	public boolean deleteContact(long id) {
		
		Contact contact;
		
		contact = this.getContact(id);
		if ( contact == null )
			return false;
		
		try{
			
			SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
			Session session = sessionFactory.openSession();
			
			//Ouverture de la transaction
			org.hibernate.Transaction tx = session.beginTransaction();
						
			session.delete(contact);
			
			tx.commit();
		
			session.close();
			
		} catch ( Exception e ){
			System.out.println("Erreur : "+e.getMessage());
			return false;
		}
		
		return true;
	}

	@Override
	public Contact getContact(long id) {
		Contact cta;

		try {
			Session session = HibernateUtil.getSessionFactory().openSession();
			
			//Ouverture de la transaction
			org.hibernate.Transaction tx = session.beginTransaction();
			
			cta = (Contact)session.get( Contact.class, id );
			//Pour charger l'adresse (lazy)
			cta.getAddress().getCity();
			
			//Pour charger les phone number (lazy)
		
			Set <PhoneNumber> tmp = cta.getPhones();
			Iterator<PhoneNumber> it = tmp.iterator();
			while(it.hasNext()){
				PhoneNumber ph = it.next();
				ph.getId();				
			}
			
			//Pour charger les groupes
			
			Set <ContactGroup> groups = cta.getBooks();
			Iterator<ContactGroup> it2 = groups.iterator();
			while(it2.hasNext()){
				ContactGroup cg = it2.next();
				cg.getGroupid();
			}
			
			tx.commit();
			
			session.close();			
		} catch ( Exception e ){
			System.out.println("Erreur : "+e.getMessage());
			cta = null;
		}
		
		return cta;
	}	
	
	
	@Override
	public boolean modifyContact(long id, String firstname, String lastname,String email, String street, String city, String zip, String country,Set<PhoneNumber> phones,Set<ContactGroup>books) {
		
		Contact c ;
		Address a ;
		
		c = this.getContact(id);
		a = c.getAddress();
		
		if ( c == null )
			return false;
		
		c.setFirstName(firstname);
		c.setLastName(lastname);
		c.setEmail(email);
		
		a.setCity(city);
		a.setCountry(country);
		a.setStreet(street);
		a.setZip(zip);				

		try{
			
			SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
			Session session = sessionFactory.openSession();
			
			//Ouverture de la transaction
			org.hibernate.Transaction tx = session.beginTransaction();				
			
			//GESTION DE LA COLLECTION PHONE NUMBER : SUPPRIME CHAQUE PHONE NUMBER ET RAJOUTE CEUX INDIQUES
			
			Iterator<PhoneNumber>it = c.getPhones().iterator();
			while(it.hasNext()){
				session.delete(it.next());
			}
			
			it = phones.iterator();
			while (it.hasNext()){				
				it.next().setContact(c);				
			}
			
			c.setPhones(phones);
			
			session.update(c);	
			
			tx.commit();
		
			session.close();		
			
		} catch ( Exception e ){
			System.out.println("Erreur : "+e.getMessage());
			return false;
		}	
		
		return true;
	}
	

	@Override
	public boolean modifyContact(Contact contact, String firstname,
			String lastname, String email, String street, String city, String zip, String country,Set<PhoneNumber> phones,Set<ContactGroup>books) {
		
		Contact c = contact;
		Address a = c.getAddress();			
		
		if ( c == null )
			return false;
		
		c.setFirstName(firstname);
		c.setLastName(lastname);
		c.setEmail(email);
		
		a.setCity(city);
		a.setCountry(country);
		a.setStreet(street);
		a.setZip(zip);	
			
		try{
			
			SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
			Session session = sessionFactory.openSession();
			
			//Ouverture de la transaction
			org.hibernate.Transaction tx = session.beginTransaction();	
			
			
			//GESTION DE LA COLLECTION PHONE NUMBER
			session.refresh(c);
			
			Iterator<PhoneNumber>it = c.getPhones().iterator();
			while(it.hasNext()){
				session.delete(it.next());
			}
			
			it = phones.iterator();
			while (it.hasNext()){				
				it.next().setContact(c);				
			}
			
			c.setPhones(phones);
			
			session.update(c);				
			
			tx.commit();
		
			session.close();
			
		} catch ( Exception e ){
			System.out.println("Erreur : "+e.getMessage());
			return false;
		}
		
		return true;	
	}
	

	@Override
	public ArrayList<Contact> getContactByFirstname(String firstname) {	
		
		ArrayList<Contact> listeContact = new ArrayList<Contact>();
		
		StringBuffer requeteS = new StringBuffer();
		requeteS.append("from Contact as c  left join fetch c.address address where c.firstName='"+firstname+"'");
		
		try{
			
			SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
			Session session = sessionFactory.openSession();
			
			//Ouverture de la transaction
			org.hibernate.Transaction tx = session.beginTransaction();
				
		
			Query req = session.createQuery(requeteS.toString());
			List resultats = req.list();
			
			Iterator it = resultats.iterator();
			while(it.hasNext()){
				Object o = it.next();
				if ( o instanceof Contact){
					Contact c = (Contact) o;
					listeContact.add(c);
				}
			}
			
			tx.commit();
		
			session.close();
			
		} catch ( Exception e ){
			System.out.println("Erreur : "+e.getMessage());
		}
		
		return listeContact;

	}

	@Override
	public ArrayList<Contact> getContactByLastname(String lastname) {
		
		/*VERSION HQL
		 * ArrayList<Contact> listeContact = new ArrayList<Contact>();
		
		StringBuffer requeteS = new StringBuffer();
		requeteS.append("from Contact as c  left join fetch c.address address where c.lastName='"+lastname+"'");
		
		try{
			
			SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
			Session session = sessionFactory.openSession();
			
			//Ouverture de la transaction
			org.hibernate.Transaction tx = session.beginTransaction();
				
		
			Query req = session.createQuery(requeteS.toString());
			List resultats = req.list();
			
			Iterator it = resultats.iterator();
			while(it.hasNext()){
				Object o = it.next();
				if ( o instanceof Contact){
					Contact c = (Contact) o;
					listeContact.add(c);
				}
			}
			
			tx.commit();
		
			session.close();
			
		} catch ( Exception e ){
			System.out.println("Erreur : "+e.getMessage());
		}
		
		return listeContact;*/
		
		
		//VERSION CRITERIA
		ArrayList<Contact> listeContact = new ArrayList<Contact>();
		
		try{
			
			SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
			Session session = sessionFactory.openSession();
			
			//Ouverture de la transaction
			org.hibernate.Transaction tx = session.beginTransaction();
			
			List results = session.createCriteria(Contact.class)
					.add(Restrictions.like("lastName", lastname) )
					.setFetchMode("address", FetchMode.EAGER)
					.setFetchMode("phones", FetchMode.EAGER)
					.setFetchMode("books", FetchMode.EAGER)
					.list();
			
			Iterator it = results.iterator();
			while(it.hasNext()){
				Object o = it.next();
				if ( o instanceof Contact){
					Contact c = (Contact) o;
					
					//Pour eviter le lazy
					
					c.getAddress().getId();
					
					Set<ContactGroup>book = c.getBooks();
					Iterator<ContactGroup> tmpgroup = book.iterator();
					while(tmpgroup.hasNext()){
						tmpgroup.next().getGroupid();
					}
					
					
					listeContact.add(c);
				}
			}
			
			tx.commit();
			
			session.close();
			
		} catch ( Exception e ){
			System.out.println("Erreur : "+e.getMessage());
			return null;
		}
		
		return listeContact;
	}

	@Override
	public ArrayList<Contact> getContactByEmail(String email) {

		/*ArrayList<Contact> listeContact = new ArrayList<Contact>();
		
		StringBuffer requeteS = new StringBuffer();
		requeteS.append("from Contact as c  left join fetch c.address address where c.email='"+email+"'");
		
		try{
			
			SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
			Session session = sessionFactory.openSession();
			
			//Ouverture de la transaction
			org.hibernate.Transaction tx = session.beginTransaction();
				
		
			Query req = session.createQuery(requeteS.toString());
			List resultats = req.list();
			
			Iterator it = resultats.iterator();
			while(it.hasNext()){
				Object o = it.next();
				if ( o instanceof Contact){
					Contact c = (Contact) o;
					listeContact.add(c);
				}
			}
			
			tx.commit();
		
			session.close();
			
		} catch ( Exception e ){
			System.out.println("Erreur : "+e.getMessage());
		}
		
		return listeContact;*/
		
		ArrayList<Contact> listeContact = new ArrayList<Contact>();
		
		try{
			
			SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
			Session session = sessionFactory.openSession();
			
			//Ouverture de la transaction
			org.hibernate.Transaction tx = session.beginTransaction();
			
			Contact contact = new Contact();
			contact.setEmail(email);
			
			List results = session.createCriteria(Contact.class)
			.add( Example.create(contact) )
			.setFetchMode("address", FetchMode.EAGER)
			.setFetchMode("phones", FetchMode.EAGER)
			.setFetchMode("books", FetchMode.EAGER)
			.list();
			
			Iterator it = results.iterator();
			while(it.hasNext()){
				Object o = it.next();
				if ( o instanceof Contact){
					Contact c = (Contact) o;
					
					//Pour eviter le lazy
					
					c.getAddress().getId();
					
					Set<ContactGroup>book = c.getBooks();
					Iterator<ContactGroup> tmpgroup = book.iterator();
					while(tmpgroup.hasNext()){
						tmpgroup.next().getGroupid();
					}
					
					
					listeContact.add(c);
				}
			}
			
			tx.commit();
			
			session.close();
			
		} catch ( Exception e ){
			System.out.println("Erreur : "+e.getMessage());
			return null;
		}
		
		return listeContact;
		
		
	}


	@Override
	public ArrayList<Contact> getAllExistingContact() {
		
		ArrayList<Contact> listeContact = new ArrayList<Contact>();
		
		StringBuffer requeteS = new StringBuffer();
		
		requeteS.append("from Contact as c left join fetch c.address address");
		
		try{
			
			SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
			Session session = sessionFactory.openSession();
			
			//Ouverture de la transaction
			org.hibernate.Transaction tx = session.beginTransaction();
				
		
			Query req = session.createQuery(requeteS.toString());
			List resultats = req.list();
			
			Iterator it = resultats.iterator();
			while(it.hasNext()){
				Object o = it.next();
				if ( o instanceof Contact){
					Contact c = (Contact) o;
					
					//Pour eviter le lazy
					Set <PhoneNumber> tmp = c.getPhones();
					Iterator<PhoneNumber> itx = tmp.iterator();
					while(itx.hasNext()){
						PhoneNumber ph = itx.next();
						ph.getId();				
					}					

					listeContact.add(c);
				}
			}
			
			tx.commit();
		
			session.close();
			
		} catch ( Exception e ){
			System.out.println("Erreur : "+e.getMessage());
		}
		
		return listeContact;
	}


	@Override
	public boolean addGroup(String groupname) {
		
		ContactGroup g ; 
		g = new ContactGroup();
		
		Set<Contact>contacts = new HashSet<>();
		g.setGroupName(groupname);
		g.setContacts(contacts);
		
		try{
			
			SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
			Session session = sessionFactory.openSession();
			
			//Ouverture de la transaction
			org.hibernate.Transaction tx = session.beginTransaction();			

			session.save(g);
			
			tx.commit();
		
			session.close();
			
		} catch ( Exception e ){
			System.out.println("Erreur : "+e.getMessage());
			return false;
		}
		
		return true;	
	}


	@Override
	public boolean deleteContactGroup(int id) {
		
		ContactGroup g = this.getContactGroup(id);
		
		if ( g == null )
			return false;
		
		try{
			
			SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
			Session session = sessionFactory.openSession();
			
			//Ouverture de la transaction
			org.hibernate.Transaction tx = session.beginTransaction();
						
			session.delete(g);
			
			tx.commit();
		
			session.close();
			
		} catch ( Exception e ){
			System.out.println("Erreur : "+e.getMessage());
			return false;
		}
		
		return true;		
	}


	@Override
	public ContactGroup getContactGroup(int id) {
		
		ContactGroup g ;
		
		try {
			Session session = HibernateUtil.getSessionFactory().openSession();
			
			//Ouverture de la transaction
			org.hibernate.Transaction tx = session.beginTransaction();
			
			g = (ContactGroup)session.get(ContactGroup.class,id);
			
			Iterator<Contact> tmp = g.getContacts().iterator();
			while (tmp.hasNext()){
				Contact c = tmp.next();
				c.getId();
			}
			
			tx.commit();
			
			session.close();			
		} catch ( Exception e ){
			System.out.println("Erreur : "+e.getMessage());
			g = null;
		}
		
		return g;
	}


	@Override
	public ContactGroup getContactGroup(String groupname) {	
		
		ContactGroup cg = null;
		
		StringBuffer requeteS = new StringBuffer();
		requeteS.append("from ContactGroup as cg  left join fetch cg.contacts as cts where cg.groupName='"+groupname+"'");
		
		
		try {
			SessionFactory facto = HibernateUtil.getSessionFactory();
			Session session = facto.openSession();
			
			//Ouverture de la transaction
			org.hibernate.Transaction tx = session.beginTransaction();
			
			Query requete = session.createQuery(requeteS.toString());
			List resultats = requete.list();
			cg = (ContactGroup)resultats.get(0);
			Iterator<Contact>it = cg.getContacts().iterator();
			while(it.hasNext()){
				Contact contact = it.next();
				contact.getId();
			}
			
			tx.commit();
			
			session.close();
		}catch ( Exception e) {
			System.out.println("Erreur : "+e.getMessage());
			return null;
		}		
		
		return cg;
	}


	@Override
	public boolean deleteContactGroup(String groupname) {
		
		ContactGroup cg = null;
		
		cg = this.getContactGroup(groupname);
		if ( cg == null ) 
			return false;		
		
		try {
			SessionFactory facto = HibernateUtil.getSessionFactory();
			Session session = facto.openSession();
			
			//Ouverture de la transaction
			org.hibernate.Transaction tx = session.beginTransaction();
			
			//Suppression du lien des contacts avec ce groupe
			
			Set<Contact>contacts = cg.getContacts();
			Iterator<Contact>it =contacts.iterator();
			while(it.hasNext()){
				Contact c = it.next();
				c.getBooks().remove(cg);
				session.update(c);
			}
						
			session.delete(cg);			
						
			tx.commit();
			
			session.close();
		}catch ( Exception e) {
			System.out.println("Erreur : "+e.getMessage());
			return false;
		}		
		
		return true;
		
	}


	@Override
	public boolean addEntreprise(int numsiret, String firstname,
			String lastname, String email, String street, String city,
			String zip, String country, Set<PhoneNumber> phones,
			Set<ContactGroup> books) {
		
		
		
		Entreprise entreprise = new Entreprise();
		
		entreprise.setNumSiret(numsiret);
		
		entreprise.setEmail(email);
		entreprise.setFirstName(firstname);
		entreprise.setLastName(lastname);	
		
		Address address = new Address();
		
		address.setCity(city);
		address.setCountry(country);
		address.setStreet(street);
		address.setZip(zip);
		
		entreprise.setAddress(address);	
		
		if ( entreprise.getPhones() == null ){
			Set<PhoneNumber>tmp = new HashSet<PhoneNumber>();
			entreprise.setPhones(tmp);
		}
		
		Iterator<PhoneNumber> it = phones.iterator();
		while (it.hasNext()){
			PhoneNumber x = it.next();
			x.setContact(entreprise);
			entreprise.getPhones().add(x);
		}
		
		Iterator<ContactGroup> it2 = books.iterator();
		while (it2.hasNext()){
			ContactGroup g = it2.next();
			if (g.getContacts() == null)
				g.setContacts(new HashSet<Contact>());
			g.getContacts().add(entreprise);
			if (entreprise.getBooks() == null)
				entreprise.setBooks(new HashSet<ContactGroup>());
			entreprise.getBooks().add(g);
			
		}
			
		try{
			
			SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
			Session session = sessionFactory.openSession();
			
			//Ouverture de la transaction
			org.hibernate.Transaction tx = session.beginTransaction();			

			session.save(entreprise);
			
			tx.commit();
		
			session.close();
			
		} catch ( Exception e ){
			System.out.println("Erreur : "+e.getMessage());
			return false;
		}
		
		return true;
		
	}


	@Override
	public ArrayList<ContactGroup> getAllExistingContactGroup() {	
		
		ArrayList<ContactGroup>listeContactGroup = new ArrayList<ContactGroup>();
		
		StringBuffer requeteS = new StringBuffer();
		
		requeteS.append("select distinct cg from ContactGroup as cg left join fetch cg.contacts");
		
		try{
			
			SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
			Session session = sessionFactory.openSession();
			
			//Ouverture de la transaction
			org.hibernate.Transaction tx = session.beginTransaction();				
		
			Query req = session.createQuery(requeteS.toString());
			
			List resultats = req.list();				
			
			Iterator it = resultats.iterator();
			while(it.hasNext()){
				
				
				Object o = it.next();
				if ( o instanceof ContactGroup){
					
					
					ContactGroup cg = (ContactGroup) o;				
					
					//Pour eviter le lazy
					Set<Contact>tmp = cg.getContacts();
					Iterator<Contact>itx = tmp.iterator();
					while(itx.hasNext()){
						Contact c = itx.next();
						c.getId();
					}
					
					listeContactGroup.add(cg);					
				}
			}
			
			tx.commit();
		
			session.close();
			
		} catch ( Exception e ){
			System.out.println("Erreur : "+e.getMessage());
			return null;
		}
		
		return listeContactGroup;
	}
	

}
